package com.atguigu.tingshu.album.service.impl;

import com.alibaba.nacos.shaded.javax.annotation.Nullable;
import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.cache.TsCache;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private AlbumAttributeValueMapper albumAttributeValueMapper;

    @Autowired
    private AlbumStatMapper albumStatMapper;

    @Autowired
    private RabbitService rabbitService;


    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;


    /**
     * 查询专辑统计信息
     * @param albumId
     * @return
     */
    @TsCache(prefix = "stat:info:")
    @Override
    public AlbumStatVo getAlbumStatVo(Long albumId) {
        //调用方法
        return albumStatMapper.selectAlbumStatVo(albumId);
    }

    /**
     * 查询专辑属性信息
     *
     * @param albumId
     * @return
     */
    @Override
    public List<AlbumAttributeValue> findAlbumAttributeValue(Long albumId) {

        return albumAttributeValueMapper.selectList(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId));

    }

    /**
     * 查询用户的所有专辑列表
     *
     * @param userId
     * @return
     */
    @Override
    public List<AlbumInfo> findUserAllAlbumList(Long userId) {
        /*//设置分页对象
        Page<AlbumInfo> albumInfoPage = new Page<>(1,20);
        //创建查询条件
        LambdaQueryWrapper<AlbumInfo> wrapper = new LambdaQueryWrapper<>();
        //设置查询条件
        wrapper.eq(AlbumInfo::getUserId, userId);
        //设置排序
        wrapper.orderByDesc(AlbumInfo::getCreateTime);
        //设置查询字段
        wrapper.select(AlbumInfo::getId, AlbumInfo::getAlbumTitle);
        return albumInfoMapper.selectPage(albumInfoPage, wrapper).getRecords();*/

        LambdaQueryWrapper<AlbumInfo> wrapper = new LambdaQueryWrapper<>();
        //设置查询条件
        wrapper.eq(AlbumInfo::getUserId, userId);
        //todo 1.设置倒序排序
        //todo 2.在末尾添加sql字段
        wrapper.orderByDesc(AlbumInfo::getId).last("limit 30");
        return albumInfoMapper.selectList(wrapper);
    }

    /**
     * 保存修改的专辑信息
     *
     * @param albumId
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateAlbumInfo(Long albumId, AlbumInfoVo albumInfoVo) {
        //获取专辑信息
        AlbumInfo albumInfo = this.getById(albumId);

        //将属性信息
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        //设置用户id
        Long userId = AuthContextHolder.getUserId() == null ? 1l : AuthContextHolder.getUserId();
        //userId进行赋值
        albumInfo.setUserId(userId);
//        albumInfo.setId(albumId);
        //将数据进行插入->数据库
        albumInfoMapper.updateById(albumInfo);

        //保存属性信息前先进行删除
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId));
        //保存属性信息
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        if (!CollectionUtils.isEmpty(albumAttributeValueVoList)) {
            for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
                //创建属性值信息
                AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                //属性拷贝
                BeanUtils.copyProperties(albumAttributeValueVo, albumAttributeValue);
                //返回的数据中是没有albmuId
                albumAttributeValue.setAlbumId(albumId);
                albumAttributeValueMapper.insert(albumAttributeValue);
            }
        }

        //判断专辑是否为上架//这里作为消息的发送者，且需要在配置文件中添加配置信息
        //    publisher-confirm-type: CORRELATED
        //    publisher-returns: true
        if ("1".equals(albumInfo.getIsOpen())) {
            //上架
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumId);
            //将专辑保存到布隆过滤器中
            RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
            bloomFilter.add(albumInfo.getId());
        } else {
            //下架
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_LOWER, albumId);
        }
    }

    /**
     * 根据id查询专辑信息
     * 用于回显
     *
     * @param albumId
     * @return
     */
    @Override
    @TsCache(prefix = RedisConstant.ALBUM_INFO_PREFIX)
    public AlbumInfo getAlbumInfoById(Long albumId) {

//        //组成缓存中的key
//        String key= RedisConstant.ALBUM_INFO_PREFIX+albumId;
//        AlbumInfo albumInfo = null;
//        try {
//            //从缓存中取出数据
//            albumInfo = (AlbumInfo) this.redisTemplate.opsForValue().get(key);
//            //对缓存中的数据进行判断
//            if(null==albumInfo){//缓存没数据
//                //缓存中是空的，需要从数据库中取数据,但是这里可能会造成缓存击穿，所以要加锁
//                String lockKey=RedisConstant.ALBUM_LOCK_SUFFIX+albumId;
//                //获取锁对象
//                RLock lock = redissonClient.getLock(lockKey);
//                //只有上锁了以后才可以对数据库进行操作
//                lock.lock();
//                try {
//                    //对数据库进行操作
//                    albumInfo = this.getAlbumInfo(albumId);
//                    System.out.println("已经查询数据库");
//                    //数据库中也可能没有数据所以进行判断
//                    if(null==albumInfo){
//                        //如果数据库中没有数据就往缓存中存储一个空数据防止请求都到数据库中
//                        redisTemplate.opsForValue().set(key,new AlbumInfo(),RedisConstant.ALBUM_TEMPORARY_TIMEOUT, TimeUnit.SECONDS);
//                        return albumInfo;
//                    }
//                    //数据库中有数据，直接将数据存储到缓存中并返回
//                    redisTemplate.opsForValue().set(key,albumInfo,RedisConstant.ALBUM_TIMEOUT,TimeUnit.SECONDS);
//                    return albumInfo;
//                } catch (Exception e) {
//                    throw new RuntimeException(e);
//                } finally {
//                    lock.unlock();
//                }
//            }else{
//                //缓存有数据
//                return albumInfo;
//            }
//        } catch (RuntimeException e) {
//            log.error(e.getMessage());
//        }
        return getAlbumInfo(albumId);
    }

    @org.jetbrains.annotations.Nullable
    private AlbumInfo getAlbumInfo(Long albumId) {
        //查询album专辑信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        //  获取属性与属性值集合数据
        if (null != albumInfo) {
            albumInfo.setAlbumAttributeValueVoList(albumAttributeValueMapper.selectList(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId)));
        }
        return albumInfo;
    }

    /**
     * 删除专辑信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAlbumInfo(Long albumId) {
        //删除专辑
        this.albumInfoMapper.deleteById(albumId);
        //删除属性值
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId));
        //  album_stat:
        albumStatMapper.delete(new LambdaQueryWrapper<AlbumStat>().eq(AlbumStat::getAlbumId, albumId));
    }

    /**
     * 根据分页查询专辑
     *
     * @param albumInfoPage
     * @param albumInfoQuery
     * @return
     */
    @Override
    public void findUserAlbumPage(Page<AlbumListVo> albumInfoPage, AlbumInfoQuery albumInfoQuery) {
        //这种情况下，只需要数据库中查询出来的数据，所以我们直接进行mapper层的调用，写sql语句
        albumInfoMapper.selectAlbumListByPage(albumInfoPage, albumInfoQuery);
    }

    /**
     * 保存专辑信息
     *
     * @param albumInfoVo(我们在保存专辑的时候,编辑的表单)
     * @param userId(当前的登录用户)
     */
    @Override
    @Transactional(rollbackFor = Exception.class)//因为是三个操作一起操作，保证原子性
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo, Long userId) {

        /**
         * 1.1保存当前登录用户的id
         * 1.2保存免费的集数
         * 1.3保存当前专辑的状态
         **/
        //我们保存的表单是albumInfoVo，但是我们需要返回去的数据应该封装在Album实体类中
        //新建一个albumInfo对象
//todo 一、先保存album_info
        //创建albumInfo对象，用于存储我们保存的对象
        AlbumInfo albumInfo = new AlbumInfo();
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        //todo 1.1保存当前登录用户的id
        albumInfo.setUserId(userId);
        //看前端传过来的付费类型是哪一种，如果是vip，就需要有一个免费试听的集数
        //todo 1.2保存免费的集数
        if (!albumInfo.getPayType().equals(SystemConstant.ALBUM_PAY_TYPE_FREE)) {
            //是这个类型对免费集数进行赋值
            albumInfo.setTracksForFree(10);
        }
        //todo 1.3保存当前专辑的状态
        albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
        /**
         * 1.1保存当前登录用户的id
         * 1.2保存免费的集数
         * 1.3保存当前专辑的状态
         * 三个前端没有传给后端的数据，且需要的数据拿到了
         * 下一步进行保存
         */
        albumInfoMapper.insert(albumInfo);

        //2.保存album_attribute_value，专辑标签值 AlbumVo存在
        //获取到Vo表单中的标签属性值的集合
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        //判断属性值是否为空，不空则保存数据
        if (!CollectionUtils.isEmpty(albumAttributeValueVoList)) {
            albumAttributeValueVoList.stream().map(albumAttributeValueVo -> {
                //创建对象
                AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                //将查询到的属性值集合
                BeanUtils.copyProperties(albumAttributeValueVo, albumAttributeValue);
                //因为每一个属性值都是在专辑分类选择好后产生的，且我们在根据属性值进行筛选专辑的时候
                //有对应的标签值的话，就可以看到我们的专辑，所以，在设置标签的时候，要设置好专辑id
                /**
                 * @TableId(type = IdType.AUTO)
                private Long id;
                 */
                albumAttributeValue.setAlbumId(albumInfo.getId());
                albumAttributeValueMapper.insert(albumAttributeValue);
                return albumAttributeValue;
            });
        }
        //3.保存album_stat 专辑统计
        this.saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_BROWSE);
        this.saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_PLAY);
        this.saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_SUBSCRIBE);
        this.saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_COMMENT);

        //判断当前专辑是否为上架
        //判断专辑是否为上架
        if ("1".equals(albumInfo.getIsOpen())) {
            //上架
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumInfo.getId());
            //将专辑保存到布隆过滤器中
            RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
            bloomFilter.add(albumInfo.getId());
        } else {
            //下架
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_LOWER, albumInfo.getId());
        }
    }

    /**
     * 为专辑生成播放量、评论量..等等
     *
     * @param albumId
     * @param albumStatPlay
     */
    public void saveAlbumStat(Long albumId, String albumStatPlay) {
        //创建数量对象
        AlbumStat albumStat = new AlbumStat();
        //设置专辑id
        //albumStat.setId(albumId);
        albumStat.setAlbumId(albumId);
        //设置统计类型
        albumStat.setStatType(albumStatPlay);
        //设置统计数目
        albumStat.setStatNum(new Random().nextInt(1000));
        albumStatMapper.insert(albumStat);
    }
}
